package logic

import (
	"context"
	"database/sql"
	"errors"
	"fmt"

	"shorturl/internal/svc"
	"shorturl/internal/types"
	"shorturl/model"
	"shorturl/pkg/base62"
	"shorturl/pkg/connect"
	"shorturl/pkg/md5"
	"shorturl/pkg/urltool"

	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

type ConvertLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewConvertLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ConvertLogic {
	return &ConvertLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

// 转链： 长链接转换短链接
func (l *ConvertLogic) Convert(req *types.ConvertRequest) (resp *types.ConvertResponse, err error) {
	// 1校验输入的数据
	// 1.1 数据不能为空
	// 1.2长链接能请求通
	if ok := connect.Get(req.LongUrl); !ok {
		return nil, errors.New("无效的链接")
	}
	// 1.3判断是否转链过
	// 通过长链接得到md5值
	md5Value := md5.Sum([]byte(req.LongUrl))
	// 通过md5值查询数据库
	u, err := l.svcCtx.ShortUrlMapModel.FindOneByMd5(l.ctx, sql.NullString{String: md5Value, Valid: true})
	if err != sqlx.ErrNotFound {
		if err == nil {
			return nil, fmt.Errorf("该链接已经转为:%v", u.Surl.String)
		}
		logx.Errorw("查询数据库失败", logx.LogField{Key: "error", Value: err})
		return nil, err
	}
	// 1.4不能是1个短链接（避免循环转链）
	pathurl, err := urltool.GetUrlPath(req.LongUrl)
	if err != nil {
		logx.Errorw("GetUrlPath error", logx.LogField{Key: "error", Value: err})
		return nil, err
	}
	_, err = l.svcCtx.ShortUrlMapModel.FindOneBySurl(l.ctx, sql.NullString{String: pathurl, Valid: true})
	if err != sqlx.ErrNotFound {
		if err == nil {
			return nil, errors.New("该链接已经是短链接")
		}
		logx.Errorw("查询数据库失败", logx.LogField{Key: "error", Value: err})
		return nil, err
	}
	var shortUrl string
	for {
		// 2取号
		id, err := l.svcCtx.Seq.Next()
		if err != nil {
			logx.Errorw("取号失败", logx.LogField{Key: "error", Value: err})
		}
		fmt.Println(id)
		// 3号码转短链
		// 安全性  将字符串打乱,并且放到配置文件中
		shortUrl = base62.IntTOString(id)
		// 黑名单
		if _, ok := l.svcCtx.ShortUrlBlackListMap[shortUrl]; !ok {
			break
		}
	}
	// 4存储 长短链接映射关系
	_,err =l.svcCtx.ShortUrlMapModel.Insert(l.ctx,&model.ShortUrlMap{
		Lurl: sql.NullString{String: req.LongUrl, Valid: true},
		Surl: sql.NullString{String: shortUrl, Valid: true},
		Md5: sql.NullString{String: md5Value,Valid: true},
	})
	if err != nil {
		logx.Errorw("mysql insert error", logx.LogField{Key: "error", Value: err})
		return nil, err
	}
	l.svcCtx.Filter.AddString(shortUrl)
	// 5返回短链接
	short :=l.svcCtx.Config.ShortDoamin + shortUrl

	return &types.ConvertResponse{
		ShortUrl: short,
	}, nil
}
